// trdpcommunicator.h
#ifndef TRDPCOMMUNICATOR_H
#define TRDPCOMMUNICATOR_H

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string>

#if defined (POSIX)
#include <unistd.h>
#elif (defined (WIN32) || defined (WIN64))
#include "getopt.h"
#endif

#include <QObject>
#include <QByteArray>
#include <map>
#include <vector>
#include "include/trdp_if_light.h"
#include "include/vos_thread.h"
#include "include/vos_utils.h"

#define APP_VERSION     "1.0"
#define DATA_MAX        1432u
#define RESERVED_MEMORY 1000000u

class TRDPHandler {
private:
    TRDP_APP_SESSION_T m_appHandle;
    bool m_initialized;
    bool m_running;

    // 管理多个发布者和订阅者
    std::map<UINT32, TRDP_PUB_T> m_publishers;
    std::map<UINT32, TRDP_SUB_T> m_subscribers;

    // 发送数据缓存
    std::map<UINT32, std::vector<UINT8>> m_sendBuffers;

    TRDP_MEM_CONFIG_T m_memConfig;
    TRDP_PROCESS_CONFIG_T m_processConfig;
    TRDP_PD_CONFIG_T m_pdConfig;

public:
    TRDPHandler() : m_initialized(false), m_running(false) {
        memset(&m_appHandle, 0, sizeof(m_appHandle));
        memset(&m_memConfig, 0, sizeof(m_memConfig));
        memset(&m_processConfig, 0, sizeof(m_processConfig));
        memset(&m_pdConfig, 0, sizeof(m_pdConfig));
    }

    ~TRDPHandler() {
        stop();
        cleanup();
    }

    const std::map<UINT32, TRDP_SUB_T>& getSubscribers() const {
        return m_subscribers;
    }

    bool init(UINT32 reservedMemory = RESERVED_MEMORY) {
        if (m_initialized) return true;

        m_memConfig.size = reservedMemory;

        // 初始化TRDP库
        if (tlc_init(&TRDPHandler::dbgOut, NULL, &m_memConfig) != TRDP_NO_ERR) {
            std::cerr << "TRDP initialization error" << std::endl;
            return false;
        }

        m_initialized = true;
        return true;
    }

    bool openSession(UINT32 ownIP = 0) {
        if (!m_initialized) {
            if (!init()) return false;
        }

        // 配置进程信息
        strncpy(m_processConfig.hostName, "TRDPCom", sizeof(m_processConfig.hostName) - 1);
        m_processConfig.cycleTime = TRDP_PROCESS_DEFAULT_CYCLE_TIME;
        m_processConfig.options = TRDP_OPTION_BLOCK;

        // 配置PD参数
        m_pdConfig.sendParam = TRDP_PD_DEFAULT_SEND_PARAM;
        m_pdConfig.flags = TRDP_FLAGS_NONE;
        m_pdConfig.timeout = 1000000u;

        // 打开会话
        if (tlc_openSession(&m_appHandle, ownIP, 0, NULL, &m_pdConfig, NULL, &m_processConfig) != TRDP_NO_ERR) {
            std::cerr << "Failed to open TRDP session" << std::endl;
            return false;
        }

        return true;
    }

    bool publish(UINT32 comId, UINT32 destIP, UINT32 interval,
                 const std::string& data = "Hello World") {
        if (m_publishers.find(comId) != m_publishers.end()) {
            std::cerr << "COMID " << comId << " already published" << std::endl;
            return false;
        }

        TRDP_PUB_T pubHandle;
        std::vector<UINT8> sendData(data.begin(), data.end());
        m_sendBuffers[comId] = sendData;

        TRDP_ERR_T err = tlp_publish(
            m_appHandle,
            &pubHandle,
            NULL, NULL,
            0u,
            comId,
            0u,
            0u,
            0u,  // 自动选择源IP
            destIP,
            interval,
            0u,
            TRDP_FLAGS_NONE,
            sendData.data(),
            sendData.size()
            );

        if (err != TRDP_NO_ERR) {
            std::cerr << "Failed to publish COMID " << comId << ": "
                      << vos_getErrorString((VOS_ERR_T)err) << std::endl;
            return false;
        }

        m_publishers[comId] = pubHandle;
        return true;
    }

    bool subscribe(UINT32 comId, UINT32 dstIP = 0, UINT32 timeout = 3000000) {
        if (m_subscribers.find(comId) != m_subscribers.end()) {
            std::cerr << "COMID " << comId << " already subscribed" << std::endl;
            return false;
        }

        TRDP_SUB_T subHandle;
        TRDP_ERR_T err = tlp_subscribe(
            m_appHandle,
            &subHandle,
            NULL,
            NULL,
            0u,
            comId,
            0,
            0,
            VOS_INADDR_ANY, VOS_INADDR_ANY,
            dstIP,
            TRDP_FLAGS_DEFAULT,
            timeout,
            TRDP_TO_SET_TO_ZERO
            );

        if (err != TRDP_NO_ERR) {
            std::cerr << "Failed to subscribe COMID " << comId << ": "
                      << vos_getErrorString((VOS_ERR_T)err) << std::endl;
            return false;
        }

        m_subscribers[comId] = subHandle;
        return true;
    }

    bool updateSession() {
        TRDP_ERR_T err = tlc_updateSession(m_appHandle);
        if (err != TRDP_NO_ERR) {
            std::cerr << "Failed to update session: "
                      << vos_getErrorString((VOS_ERR_T)err) << std::endl;
            return false;
        }
        return true;
    }

    bool sendData(UINT32 comId, const std::string& data) {
        auto it = m_publishers.find(comId);
        if (it == m_publishers.end()) {
            std::cerr << "COMID " << comId << " not published" << std::endl;
            return false;
        }

        m_sendBuffers[comId] = std::vector<UINT8>(data.begin(), data.end());

        TRDP_ERR_T err = tlp_put(
            m_appHandle,
            it->second,
            m_sendBuffers[comId].data(),
            m_sendBuffers[comId].size()
            );

        if (err != TRDP_NO_ERR) {
            std::cerr << "Failed to send data for COMID " << comId << std::endl;
            return false;
        }

        return true;
    }

    bool receiveData(UINT32 comId, TRDP_PD_INFO_T& pdInfo,
                     UINT8* buffer, UINT32& bufferSize) {
        auto it = m_subscribers.find(comId);
        if (it == m_subscribers.end()) {
            return false;
        }

        TRDP_ERR_T err = tlp_get(
            m_appHandle,
            it->second,
            &pdInfo,
            buffer,
            &bufferSize
            );

        return (err == TRDP_NO_ERR);
    }

    void processEvents() {
        TRDP_FDS_T rfds;
        TRDP_SOCK_T noDesc;
        TRDP_TIME_T tv;
        const TRDP_TIME_T max_tv = { 1, 0 };
        const TRDP_TIME_T min_tv = { 0, TRDP_PROCESS_DEFAULT_CYCLE_TIME };

        FD_ZERO(&rfds);
        tlc_getInterval(m_appHandle, &tv, &rfds, &noDesc);

        // 调整超时时间
        if (vos_cmpTime(&tv, &max_tv) > 0) {
            tv = max_tv;
        }
        if (vos_cmpTime(&tv, &min_tv) < 0) {
            tv = min_tv;
        }

        // 等待事件
        int rv = vos_select(noDesc, &rfds, NULL, NULL, &tv);

        // 处理TRDP事件
        (void)tlc_process(m_appHandle, &rfds, &rv);
    }

    void run() {
        m_running = true;
        INT32 counter = 0;

        while (m_running) {
            processEvents();

            // 接收数据并显示
            for (auto& sub : m_subscribers) {
                UINT32 comId = sub.first;
                TRDP_PD_INFO_T pdInfo;
                UINT8 buffer[DATA_MAX];
                UINT32 bufferSize = DATA_MAX;

                if (receiveData(comId, pdInfo, buffer, bufferSize) && bufferSize > 0) {
                    std::cout << "\nReceived from COMID " << comId << ":" << std::endl;
                    std::cout << "Type = " << (char)(pdInfo.msgType >> 8)
                              << (char)(pdInfo.msgType & 0xFF) << ", ";
                    std::cout << "Seq = " << pdInfo.seqCount << ", ";
                    std::cout << "Size = " << bufferSize << " Bytes" << std::endl;

                    // 打印十六进制
                    for (UINT32 i = 0; i < bufferSize; ++i) {
                        printf("%02hhx ", buffer[i]);
                        if ((i + 1) % 16 == 0) printf("\n");
                    }
                    printf("\n");

                    // 打印字符串
                    std::cout << "Data: " << std::string((char*)buffer, bufferSize) << std::endl;
                }
            }

            // 更新并发送数据
            for (auto& pub : m_publishers) {
                UINT32 comId = pub.first;
                std::string data = "Counter for COMID " + std::to_string(comId) + ": " + std::to_string(counter);
                sendData(comId, data);
            }

            counter++;
            fprintf(stdout, ".");
            fflush(stdout);
        }
    }

    void stop() {
        m_running = false;
    }

    void cleanup() {
        // 取消订阅
        for (auto& sub : m_subscribers) {
            tlp_unsubscribe(m_appHandle, sub.second);
        }
        m_subscribers.clear();

        // 取消发布
        for (auto& pub : m_publishers) {
            tlp_unpublish(m_appHandle, pub.second);
        }
        m_publishers.clear();

        // 关闭会话
        tlc_closeSession(m_appHandle);

        // 终止TRDP库
        if (m_initialized) {
            tlc_terminate();
            m_initialized = false;
        }
    }

    static void dbgOut(void* pRefCon, TRDP_LOG_T category, const CHAR8* pTime,
                       const CHAR8* pFile, UINT16 LineNumber, const CHAR8* pMsgStr) {
        const char* catStr[] = { "**Error:", "Warning:", "   Info:", "  Debug:", "   User:" };
        const CHAR8* pF = strrchr(pFile, VOS_DIR_SEP);

        if (category != VOS_LOG_DBG) {
            printf("%s %s %s:%d %s",
                   pTime,
                   catStr[category],
                   (pF == NULL) ? "" : pF + 1,
                   LineNumber,
                   pMsgStr);
        }
    }
};

// 命令行参数解析辅助函数
uint32_t ipToUint(const std::string& ip);
void usage(const char* appName);

class TrdpCommunicator : public QObject {
    Q_OBJECT

public:
    explicit TrdpCommunicator(QObject *parent = nullptr);
    ~TrdpCommunicator();

    bool start(const QString& ownIp, const QString& remoteIp,
               const std::map<UINT32, UINT32>& publishers, // COMID -> 发送间隔(us)
               const std::vector<UINT32>& subscribers);     // 订阅的COMID列表
    void stop();

    void sendData(UINT32 comId, const QByteArray& data);

signals:
    void dataReceived(const QByteArray& data, UINT32 comId);
    void finished();

private slots:
    void processEvents();
    void onThreadFinished();

private:
    class TRDPHandler* m_trdpHandler;
    bool m_running;
    QThread* m_eventThread;
};

#endif // TRDPCOMMUNICATOR_H
